/******************************************************************************

	COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2009, 2010.

	This file is part of Maxsi Engine.

	Maxsi Engine is free software: you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or (at your
	option) any later version.

	Maxsi engine is distributed in the hope that it will be useful, but WITHOUT
	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
	FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
	for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with Maxsi Engine. If not, see <http://www.gnu.org/licenses/>.

	MaxsiEngine.dll
	A general purpose C++ library for the Maxsi Technology Project.

	MaxsiWin32.cpp
	Basic Win32 Functionallity.

******************************************************************************/

//=============================================================================
//	Todo: I consider most of the stuff in this file deprecated and it should be
//	replaced by a more elegant system. Plus we need to replace it to something
//	more exact like, MaxsiWinAPI.cpp - Which is preferred over Win32 API.
//=============================================================================

#ifndef MaxsiWin32_H
#define MaxsiWin32_H

//=============================================================================
//	Forward Declarations
//=============================================================================
BeginMaxsiUINamespace
class MaxsiUI_Form;
EndMaxsiUINamespace


BeginMaxsiNamespace

//=============================================================================
//	String Function Redirection Macros
//=============================================================================
#ifdef ME_USE_MULTIBYTE_STRING

	#define SendMessageM SendMessageW
	#define CreateWindowM CreateWindowW
	#define GetWindowLongM GetWindowLongW
	#define WSAAddressToStringM WSAAddressToStringW
	#define FormatMessageM FormatMessageW
	#define WNDCLASSM WNDCLASSW
	#define RegisterClassM RegisterClassW
	#define MessageBoxM MessageBoxW

#else

	#define SendMessageM SendMessageA
	#define CreateWindowM CreateWindowA
	#define GetWindowLongM GetWindowLongA
	#define WSAAddressToStringM WSAAddressToStringA
	#define FormatMessageM FormatMessageA
	#define WNDCLASSM WNDCLASSA
	#define RegisterClassM RegisterClassA
	#define MessageBoxM MessageBoxA

#endif


//=============================================================================
//	ME_Thread_Parameters - Thread creation parameters or something deprecated
//=============================================================================
struct	ME_Thread_Parameters
{
	int		Command;
	int		Parameter;
	int		nCmdShow;
	HWND	Parent;
};

//=============================================================================
//	Exception Filters - Triggers minidump generation on VS builds
//	Todo: We really need a way to debug stuff using MinGW and gdb!
//=============================================================================
#ifndef __MINGW_H
typedef LONG (WINAPI* type_ExceptionFilter  ) (__in struct _EXCEPTION_POINTERS *ExceptionInfo );
LINK type_ExceptionFilter ME_GetExceptionFilter();
#else
LINK void* ME_GetExceptionFilter();
#endif

//=============================================================================
// Basic Interthread Commands
//=============================================================================
#define ME_Thread_Cmd_Null							0x0000
#define ME_Thread_Cmd_Create						0x0001
#define ME_Thread_Cmd_GetDefaultStackSpace			0x0002
#define ME_Thread_Cmd_Register						0x0003
#define ME_Thread_Cmd_Initialize					0x0004
#define ME_Thread_Cmd_Terminate						0x0005
#define ME_Thread_Cmd_TerminateSubThread			0x0006
#define ME_Thread_Cmd_TerminateSubThreads			0x0007
#define ME_Thread_Cmd_TerminateButLeaveSubThreads	0x0008
#define ME_Thread_Cmd_SetParent						0x0009
#define ME_Thread_Cmd_GetME_WindowPointer			0x000A

//=============================================================================
// Advanced Interthread Commands
//=============================================================================
#define ME_Thread_Cmd_GetThreadList					0x0100

//=============================================================================
// Debug/Release Macros, assertion failures, etc.
//=============================================================================
#define ME_Assertion_Failure						0xF000

#define ME_TODO(Information) \
{	ME_DEBUG_BREAKPOINT \
	MESTR* Line	= UIToA((unsigned int)__LINE__); \
	MESTR* Error = BuildString(6, Information, \
		_MESTR( "\n\nThe application tried to run unimplemented code in " __FILE__ " in "), __FUNCTION__, _MESTR(" on line "), Line, _MESTR( " built on " __DATE__ "\n\n"  \
		"Execution can continue, but the behavior of the program is undefined and it is recommended to " \
		"terminate the program and restart. This error shouldn't happen so please contact Maxsi Support " \
		"at http://www.maxsi.dk/support/ so that we can fix the error.\n\n" \
		"Hit Abort to stop execution.\n" \
		"Hit Retry to continue execution and continue recieving errors.\n" \
		"Hit Ignore to continue execution but ignore any further errors.") ); \
	delete[] Error; \
	delete[] Line;	}

#ifdef _DEBUG
#define	ME_DEBUG_BREAKPOINT __debugbreak();
#define ME_TODO_DEBUG(Information) ME_TODO(Information)
#define ME_TODO_RELEASE(Information) __noop
#define	ME_DONT_COMPILE_RELEASE_BUILD __noop
#elif defined(DEBUG_RELEASE_BUILD)
#define	ME_DEBUG_BREAKPOINT // __debugbreak();
#define ME_TODO_DEBUG(Information) ME_TODO(Information)
#define ME_TODO_RELEASE(Information) __noop
#define	ME_DONT_COMPILE_RELEASE_BUILD __noop
#else
#define	ME_DEBUG_BREAKPOINT
#define ME_TODO_DEBUG(Information) __noop
#define ME_TODO_RELEASE(Information) ME_TODO(Information)
#define	ME_DONT_COMPILE_RELEASE_BUILD TODO_Implement_Code_Around_Here

#endif

#define ME_UNDEFINED_BEHAVIOR(Information) \
{	ME_DEBUG_BREAKPOINT \
	MESTR* Line	= UIToA((unsigned int)__LINE__); \
	MESTR* Error = BuildString(4, Information, \
		_MESTR("\n\nA non-fatal error was detected in " __FILE__ " in " __FILE__ " in "), __FUNCTION__, _MESTR(" on line "), Line, _MESTR( " built on " __DATE__ "\n\n"  \
		"Execution can continue, but the behavior of the program is undefined and it is recommended to " \
		"terminate the program and restart. This error shouldn't happen so please contact Maxsi Support " \
		"at http://www.maxsi.dk/support/ so that we can fix the error.\n\n" \
		"Hit Abort to stop execution.\n" \
		"Hit Retry to continue execution and continue recieving errors.\n" \
		"Hit Ignore to continue execution but ignore any further errors.") ); \
	if ( IssueMEAssertionFailure(Error) == false && ME_GetExceptionFilter() != NULL ) \
	{ \
		throw Information; \
	} \
	delete[] Error; \
	delete[] Line; \
}

#define ME_UNDEFINED_BEHAVIORMESTRC(Information) \
{	ME_DEBUG_BREAKPOINT \
	if ( IssueMEAssertionFailure(_MESTR(Information)) == false && ME_GetExceptionFilter() != NULL ) \
	{ \
		throw _MESTR(Information); \
	} \
}

#ifdef _DEBUG
#define	ME_UNDEFINED_BEHAVIOR_DEBUG(Information) ME_UNDEFINED_BEHAVIOR(Information)
#elif defined(DEBUG_RELEASE_BUILD)
#define	ME_UNDEFINED_BEHAVIOR_DEBUG(Information) __noop
#else
#define	ME_UNDEFINED_BEHAVIOR_DEBUG(Information) __noop
#endif


//=============================================================================
// Custom Interthread Commands
//=============================================================================

// Everything below 0xFFFF is reserved while anything above is custom
#define ME_Thread_Cmd_Custom						0xFFFF

// Flags for ME_Thread_Cmd_Terminate
#define	ME_Thread_Cmd_FullTermination				0x0000
#define	ME_Thread_Cmd_SelfTerminate					0x0001
#define	ME_Thread_Cmd_TerminateChildren				0x0002


//=============================================================================
// Declares the interface to call into a thread
//=============================================================================
#define	ME_THREAD(Name,Class) THREADED_VARIABLE Class* d_##Class; DWORD WINAPI Name(LPVOID parameter) { d_##Class = new Class; DWORD Result = d_##Class->EntryPoint(parameter); delete d_##Class; delete[] (char*)parameter; return Result; } \
LRESULT APIENTRY	Name##Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return d_##Class->WindowProc(hWnd,message,wParam,lParam); }

#define	ME_THREAD_H(Name,Class) \
DWORD WINAPI Name (LPVOID parameter);  \
LRESULT APIENTRY	Name##Proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

#define	ME_THREAD_LINK(Name,Class,Linking)  THREADED_VARIABLE Class* d_##Class; Linking DWORD WINAPI Name(LPVOID parameter) { d_##Class = new Class; DWORD Result = d_##Class->EntryPoint(parameter); delete d_##Class; delete[] (char*)parameter; return Result; } \
Linking LRESULT APIENTRY	Name##Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return d_##Class->WindowProc(hWnd,message,wParam,lParam); }

#define	ME_THREAD_LINK_H(Name,Class,Linking) \
Linking DWORD WINAPI Name (LPVOID parameter);  \
Linking LRESULT APIENTRY	Name##Proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);


//=============================================================================
// Declares the interface to call into a thread
//=============================================================================
#define	ME_WIN32ENTRYPOINT(ApplicationClass) ApplicationClass Application; \
int WINAPI			WinMain					(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) \
{ \
	SetWin32EntryPointClass(dynamic_cast<ME_Win32Entry*>(&Application)); \
	return Application.WinMain(hInstance,hPrevInstance,lpCmdLine,nCmdShow); \
} \
LRESULT APIENTRY ApplicationClass##Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) \
{ \
	return	Application.WindowProc(hWnd,message,wParam,lParam); \
}

#define	ME_WIN32ENTRYPOINT_H(ApplicationClass) \
int WINAPI			WinMain					(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); \
LRESULT APIENTRY ApplicationClass##Proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

//=============================================================================
//	ME_Window - A class that handles window messages and has a window.
//=============================================================================
CLASSLINK ME_Window
{
public:
	ME_Window();
	~ME_Window();

	virtual		BOOL				InitApplication		(HANDLE hInstance);
	virtual		BOOL				InitInstance		(HINSTANCE hInstance, INT nCmdShow);
	virtual		LRESULT APIENTRY	WindowProc			(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
	virtual		BOOL				TerminateApplication(void);

public:
	HWND			WindowHWND;
	MaxsiUI::MaxsiUI_Form*	Form;
	List			SubWindows;

};

//=============================================================================
//	ME_Thread - A class that handles a thread
//=============================================================================
CLASSLINK	ME_Thread : public ME_Window
{
	Declare_Class(ME_Thread,ME_Window);

public:
	ME_Thread();
	~ME_Thread();

	virtual		DWORD WINAPI		EntryPoint			(LPVOID parameter);
	virtual		DWORD				DefaultStackSpace	(void);
	virtual		LRESULT APIENTRY	WindowProc			(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
	virtual		LRESULT				ME_Thread_Cmd		(HWND hWnd, WPARAM wParam, LPARAM lParam);

	// Commands

	virtual		DWORD				OnThreadRegistered	(HWND hWnd);
	virtual		DWORD				OnThreadInitialize	(LPARAM lParam);
	virtual		DWORD				OnThreadTerminate	(LPARAM lParam);
	virtual		DWORD				OnNewParent			(HWND hWnd);
	virtual		DWORD				OnMEAssertionFailure(char* Message);

public:
	HACCEL		hAccTable;
	HINSTANCE	hInst;
	HWND		Parent;
	List		SubThreads;

};

//=============================================================================
//	ME_Win32Entry - The initial thread in a program.
//=============================================================================
CLASSLINK	ME_Win32Entry : public ME_Thread
{
	Declare_Class(ME_Win32Entry,ME_Thread);

public:
	virtual		int WINAPI			WinMain				(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
				BOOL				InitApplication		(HANDLE hInstance);
				BOOL				InitInstance		(HINSTANCE hInstance, INT nCmdShow);
	virtual		LRESULT APIENTRY	WindowProc			(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

};

//=============================================================================
//	Sort of useful general purpose functions that are utterly horrible.
//=============================================================================
LINK			HANDLE				ME_CreateThread			(LPTHREAD_START_ROUTINE lpStartAddress, HWND Parent = 0);
LINK			BOOL				ME_PostThreadMessage	(HWND hWnd, WPARAM wParam, LPARAM lParam);
LINK			LRESULT				ME_SendThreadMessage	(HWND hWnd, WPARAM wParam, LPARAM lParam);
LINK			ME_Window*			ME_WindowGetPointer		(HWND Handle);
LINK	const	UINT				ME_ThreadMessageIDFunc	(void);
#define	ME_ThreadMessageID			ME_ThreadMessageIDFunc	()
LINK			bool				SetWin32EntryPointClass	(ME_Win32Entry* NewEntry);
LINK			bool				IssueMEAssertionFailure	(MESTR* Message);

EndMaxsiNamespace

#endif
